const beginLine = document.getElementById('begin') // 起点
const endLine = document.getElementById('end')  // 终点
const timeSpan = document.querySelector('.time-span')  // 计时文本
const resetBtn = document.getElementById('reset') // 重置按钮
const playBtn = document.getElementById('play')   // 开始按钮
const methodSelect = document.getElementById('method') // 方法下拉选择
// const beginTime = Date.now()

class Player { // 玩家类
  id
  img
  minSpeed = 0  // 最小速度
  maxSpeed = 0  // 最大速度
  minDuration = 0 // 最小时间间隔
  maxDuration = 0 // 最大时间间隔
  size
  failRate = 0 // 出错几率

  el = null // dom元素
  timer = 0 // 定时器属性
  resolve = null
  reject = null
  beginTime = null

  constructor(id, img, minSpeed, maxSpeed,
              minDuration, maxDuration, size, failRate) {
    this.id = id
    this.img = img
    this.minSpeed = minSpeed
    this.maxSpeed = maxSpeed
    this.minDuration = minDuration
    this.maxDuration = maxDuration
    this.size = size
    this.failRate = failRate

    this.el = this.create()
  }
  getHtml() {
    return `<div class="player-frame" style='width: ${this.size}px'>
    <div class='player-time'>0</div>
    <div class="player" >
      <img src="${this.img}"  style='width: ${this.size}px'/>
    </div>
  </div>`
  }
  create() { // 创建并添加dom元素
    const div = document.createElement('div')
    div.innerHTML = this.getHtml()
    let dom = div.childNodes[0]
    document.body.appendChild(dom)
    return dom
  }
  get left() { return this.getPosition().left }
  set left(v) { this.el.style.left = `${v}px`}
  get right() { return this.getPosition().right}
  set right(v) { this.el.style.right = `${v}px`}
  get top() { return this.getPosition().top}
  set top(v) { this.el.style.top = `${v}px`}
  get bottom() { return this.getPosition().bottom}
  set bottom(v) { this.el.style.bottom = `${v}px`}
  getPosition() { // 得到定位
    const keys = ['x', 'y', 'width', 'height', 'top',
                  'left', 'right', 'bottom']
    const _rect = this.el.getBoundingClientRect()
    const rect =  keys.reduce((r, key) => {
      r[key] = _rect[key]
      return r
    }, {})
    rect.bottom = window.innerHeight - rect.bottom;
    rect.right = window.innerWidth - rect.right;
    return rect
  }
  getNextDistance() {// 下次移动距离
    return this.minSpeed
        + (this.maxSpeed - this.minSpeed) * Math.random()
  }
  isFinished() { // 探测是否到达终点
    const endLineLeft = endLine.getBoundingClientRect().left
    return this.left + this.size >= endLineLeft
  }
  fail() {
    this.el.querySelector('.player').classList.add('fail')
    this.reject(this)
  }
  move() { // 移动
    this.left = this.left + this.getNextDistance()
  }
  updateTime() {
    this.el.querySelector('.player-time').innerText =
      ((Date.now() - this.beginTime)/1000).toFixed(1)
  }
  tick() { // 定时器每次运行
    this.updateTime()
    if (Math.random() < this.failRate) {
      this.fail()
    } else {
      this.move()
      if (this.isFinished())  {
        this.resolve(this)
      } else {
        this.timer = setTimeout(
          () => {
            this.tick()
          },
          this.minDuration
            + (this.maxDuration-this.minDuration)*Math.random()
        )
      }
    }
  }
  start() { // 开始
    this.beginTime = Date.now()
    const promise = new Promise((resolve, reject) => {
      this.resolve = resolve
      this.reject = reject
    })
    this.tick()
    return promise
  }
  stop() { // 结束
    if (this.timer) {
      clearTimeout(this.timer)
      this.resolve = null
      this.reject = null
    }
  }
  reset() { // 重置
    this.el.querySelector('.player').classList.remove('fail')
  }
}

class Game {
  players = []
  begin = 0
  constructor(players) {
    this.players = players
    this.reset()
  }
  start() {
    this.begin = Date.now()
    const promises = this.players.map(player => player.start())
    let method = methodSelect.value
    Promise[method](promises).then((r) => {
      console.log(r)
    }).catch(e => {
      console.log(e)
    }).finally(() => {
      this.stop()
      timeSpan.innerText = ((Date.now() - this.begin)/1000).toFixed(1)
    })
  }
  stop() {
    this.players.forEach(player => player.stop())
  }
  reset() {
    let top = 30
    timeSpan.innerText = 0
    this.players.forEach(player => {
      player.reset()
      const beginLineLeft = beginLine.getBoundingClientRect().left
      player.left = beginLineLeft - player.getPosition().width
      player.top = top
      top += player.getPosition().height + 10
    })
  }
}

// test

// const p = new Player(
//   '悟空', './images/mj.gif', 11, 14, 80, 180, 120, 0.001
// )
// const beginLineLeft = beginLine.getBoundingClientRect().left
// p.right = window.innerWidth - beginLineLeft
// p.top = 30

const images =
  ['./images/wukong.gif', './images/sonic.gif','./images/mj.gif']
let game = null
Promise.all(
  ['./images/wukong.gif', './images/sonic.gif','./images/mj.gif']
  .map(url => loadImage(url))
).then(
  () => {
    game = new Game(
      [
      new Player('悟空', './images/wukong.gif', 11, 14, 80, 180, 80, 0.00),
      new Player('Sonic', './images/sonic.gif', 8, 20, 140, 220, 80, 0.001),
      new Player('僵尸', './images/mj.gif', 5, 13, 80, 50, 80, 0),
      // new Player('悟空', './images/wukong.gif', 11, 14, 80, 180, 80, 0.001),
      // new Player('Sonic', './images/sonic.gif', 8, 20, 140, 220, 80, 0.105),
      // new Player('僵尸', './images/mj.gif', 5, 13, 80, 50, 80, 0.105),
      ]
    )

    resetBtn.onclick = () => game.reset()
    playBtn.onclick = () => game.start()
  }
)

